#pragma once

#include "SpinLock.h"
#include "BufList.h"
#include "BufBlock.h"
#include "BufChunkMgr.h"

#define BLOCK_SIZE 2048

template <typename CLock = CFakeLock>
class CBufBlockMgr
{
    typedef CBufList<BufBlock, CLock> CBlockList;
    typedef typename CBlockList::ListNode BlockNode;

public:
    CBufBlockMgr(CBufChunkMgr<CLock> *pChunks) : m_pChunks(pChunks) {}
    ~CBufBlockMgr() {}

    void *operator new(size_t, void *ptr) _GLIBCXX_USE_NOEXCEPT { return ptr; }
    void operator delete(void *ptr) {}

    void Destroy() {}

public:
    BlockNode *GetBlock()
    {
        BlockNode *pNode = nullptr;

        if (m_lstFree.IsEmpty())
            pNode = NewBlock();
        else
            pNode = (BlockNode *)m_lstFree.PopFront();

        if (nullptr != pNode)
        {
            pNode->pBuf = (uint8_t *)pNode + sizeof(BlockNode);
            pNode->nEnd = BLOCK_SIZE - sizeof(BlockNode);
            pNode->nRead = pNode->nWrite = 0;
        }

        return pNode;
    }

    bool FreeBlock(BlockNode *pNode)
    {
        if (nullptr == pNode)
            return false;

        return m_lstFree.PushBack(pNode);
    }

private:
    BlockNode *NewBlock()
    {
        void *ptr = nullptr;
        BlockNode *pNode = nullptr;

        if (nullptr == m_pChunks)
            return nullptr;

        ptr = m_pChunks->Alloc(BLOCK_SIZE);

        if (nullptr != ptr)
            pNode = (BlockNode *)m_lstFree.NewNode(ptr);

        return pNode;
    }

    void DeleteBlock(BlockNode *pNode)
    {
    }

private:
    CBlockList m_lstFree;
    CBufChunkMgr<CLock> *const m_pChunks;
};
